﻿// Time.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <stdlib.h>

#include <string>
#include <thread>

#include "MyTime.h"
#include "MyList.h"

const char* const HINT_FORMAT_ERROR = "Mind format, please input again:";
MyTime ALARM(7, 30, 0);

bool alarm_mode = false;

struct Event
{
	char context[100];
	char location[50];
	MyTime start;
	MyTime elapsed;

	void print_info()
	{
		printf("Context:%s\nLocation:%s\nStart Time:%s\nEnd Time:%s\n", 
			context, 
			location, 
			start.gen_str_cpp11().get(),
			(start + elapsed).gen_str_cpp11().get());
	}
};

void print_event(Event* e)
{
	e->print_info();
	printf("\n");
}

bool compare_by_start_time(Event* ld, Event* d)
{
	return ld->start < d->start;
}

bool input_check(Event* ld, Event* d)
{
	if (strcmp(ld->location, d->location) != 0)
	{
		if (!d->start.between(ld->start, ld->elapsed + TEN_MINUTES) && !ld->start.between(d->start, d->elapsed + TEN_MINUTES))
			return true;
	}
	else
	{
		if (!d->start.between(ld->start, ld->elapsed))
			return true;
	}
	printf("illegal insert, restart.\n");
	return false;
}

bool compare_by_context(Event* ld, Event* d)
{
	return strcmp(ld->context, d->context) < 0;
}

bool find_by_time(Event* ld, void* time)
{
	MyTime* pTime = (MyTime*)time;
	return pTime->between(ld->start, ld->elapsed);
}

bool strincludes(char* s, char* c)
{
	int i = 0, j = 0;
	bool flag = false;
	int slen = strlen(s);
	int clen = strlen(c);
	while (i < slen && j < clen) 
	{
		if (s[i] == c[j])
		{
			i++;
			j++;
			if (j == clen)
			{
				return true;
			}
		}
		else
		{
			i -= j;
			i++;
			j = 0;
		}
	}
	return false;
}

void run()
{
	using std::thread;
	using std::cin;
	bool running = true;
	MyList<Event> todayEvents;
	thread alarm_thread([&]()
		{
			while (running)
			{
				time_t t = time(nullptr);
				if (ALARM == t)
				{
					printf("Time to do your lists!!!!\n");
					todayEvents.for_each(print_event);
					std::this_thread::sleep_for(std::chrono::hours(23));
				}
				std::this_thread::sleep_for(std::chrono::seconds(1));
			}
		});
	while (running)
	{
		printf("Please input your opreation(input -1 and enter for help(numbers only)):\n");
		char cmdbuf[10];
		cin >> cmdbuf;
		getchar();
		bool legal = true;
		for (int i = 0; cmdbuf[i] != '\0' && i < 10; ++i)
		{
			if (!isdigit(cmdbuf[i]) && cmdbuf[0] != '-')
			{
				legal = false;
				break;
			}
		}
		int cmd;
		if (legal)
		{
			cmd = atoi(cmdbuf);
		}
		else
		{
			printf(HINT_FORMAT_ERROR);
			printf("\n");
			continue;
		}
		switch (cmd)
		{
		case -1:
			printf(
				"-1. help\n"
				"0. add an event\n"
				"1. list all events by time\n"
				"2. list all events by context\n"
				"3. search events by keyword\n"
				"4. search a event by time\n"
				"5. remove event by uid\n"
				"6. modify a event's time by uid\n"
				"7. start alarm mode(you can do nothing util exit)\n"
				"8. list all the events\n"
				"9. exit\n");
			break;
		case 0:
		{
			bool success = false;
			while (!success)
			{
				Event* e = new Event;
				printf("Please input a event:\n");
				printf("Context:");
				gets_s(e->context, 100);

				printf("Locate:");
				gets_s(e->location, 50);

				printf("Start Time(e.g. xx:xx:xx):");
				char tbuffer[10];
				gets_s(tbuffer, 10);
				while (!MyTime::is_day_time(tbuffer)) {
					printf(HINT_FORMAT_ERROR);
					gets_s(tbuffer, 10);
				}
				e->start = MyTime(tbuffer);

				printf("Time Spend(e.g. xx:xx:xx):");
				gets_s(tbuffer, 10);
				
				while (!MyTime::is_day_time(tbuffer)) {
					printf(HINT_FORMAT_ERROR);
					gets_s(tbuffer, 10);
				}
				e->elapsed = MyTime(tbuffer);
				success = todayEvents.insert(e, compare_by_start_time, input_check);
			}
			break;
		}
		case 2:
		{
			auto temp = todayEvents.filter_collect(nullptr, nullptr, compare_by_context);
			temp->for_each(print_event);
			delete temp;
			break;
		}
		case 3:
		{
			printf("Type a keyword:");
			char keyword[100];
			gets_s(keyword, 100);
			auto temp = todayEvents.fuzzy_search([](auto e, void* kwd) -> bool
				{
					char* kword = (char*)kwd;
					return strincludes(e->context, kword);
				}, keyword);
			temp->for_each(print_event);
			delete temp;
			break;
		}
		case 4:
		{
			printf("Type the time(eg. XX:XX:XX) or anything(now):");
			char tbuffer[10];
			MyTime time;
			
			gets_s(tbuffer, 10);
			
			if (MyTime::is_day_time(tbuffer))
			{
				time = MyTime(tbuffer);
			}
			else
			{
				time = MyTime();
			}
			auto e = todayEvents.search(find_by_time, &time);
			if (e)
			{
				printf("UID:%d\n", e->UID);
				e->data->print_info();
				printf("\n");
			}
			else
			{
				printf("Not found.You have nothing to do. ;)\n");
			}
			break;
		}
		case 5:
		{
			printf("Type a UID(You can find it by list them, input -1 to back):");
			int n;
			scanf_s("%d", &n);
			getchar();
			printf("Are you sure?(y/N)");
			char op = getchar();
			if (op == 'y')
			{
				todayEvents.remove(n);
			}
			break;
		}
		case 6:
		{
			printf("Type a UID(You can find it by list them):");
			int n;
			scanf_s("%d", &n);
			auto e = todayEvents.find(n);
			if (e)
			{
				printf("Type start time (e.g. XX:XX:XX):");
				int h, m, s;
				scanf_s("%d:%d:%d", &h, &m, &s);
				e->data->start = MyTime(h, m, s);

				printf("Type spended time (e.g. XX:XX:XX):");
				scanf_s("%d:%d:%d", &h, &m, &s);
				e->data->elapsed = MyTime(h, m, s);
			}
			else
			{
				printf("Failed to find %d\n", n);
			}
			break;
		}
		case 7:
		{
			printf("Are you sure?(the program will in this mode util stop)(y/N)");
			char op = getchar();
			if (op == 'y')
			{
				printf("Input \"stop\" to stop.\n");
				alarm_mode = true;
				thread checking_thread([&todayEvents]()
					{
						while (alarm_mode)
						{
							time_t t = time(nullptr);
							tm tim;
							localtime_s(&tim, &t);
							MyTime clock(tim.tm_hour, tim.tm_min, tim.tm_sec);
							auto i = todayEvents.search(find_by_time, &clock);
							if (i != nullptr && clock.between(i->data->start, i->data->elapsed))
							{
								printf("It's time!\n");
								print_event(i->data);
								std::this_thread::sleep_for(std::chrono::seconds(i->data->elapsed.sec()));
							}
							else
							{
								std::this_thread::sleep_for(std::chrono::seconds(1));
							}
						}
					});
				while (alarm_mode)
				{
					char cmd[50];
					gets_s(cmd, 50);
					if (strcmp(cmd, "stop") == 0)
					{
						alarm_mode = false;
						checking_thread.join();
					}
				}
			}
			break;
		}
		case 1:
		case 8:
			todayEvents.for_each(print_event);
			break;
		case 9:
		{
			printf("Are you sure?(y/N)");
			char op = getchar();
			if (op == 'y')
			{
				running = false;
				alarm_thread.join();
			}
			break;
		}
		default:
			printf("?\n");
			break;
		}
	}
}

int main(int argc, char** argv)
{
	run();
}